import * as Cesium from 'cesium';

export class Primitive {
  constructor(cesiumManager) {
    this.cesiumManager = cesiumManager;
    this.primitives = new Map(); // 用于存储和管理primitive对象
    // 添加图元类型分类，便于管理和性能优化
    this.primitiveTypes = new Map();
  }

  /**
   * 添加Primitive到场景中
   * @param {Object} primitiveOptions - Primitive配置选项
   * @param {String} id - Primitive的唯一标识符
   * @returns {Primitive} 添加的Primitive对象
   */
  add(primitiveOptions, id) {
    if (!this.cesiumManager || !this.cesiumManager.viewer) {
      throw new Error('Cesium manager or viewer is not initialized');
    }

    // 如果没有提供ID，则生成一个唯一的ID
    if (!id) {
      id = this._generateId();
    }

    // 创建Primitive对象
    let primitive;
    if (primitiveOptions instanceof Cesium.Primitive) {
      primitive = primitiveOptions;
    } else {
      primitive = new Cesium.Primitive(primitiveOptions);
    }

    // 将Primitive添加到场景中
    const scenePrimitive = this.cesiumManager.viewer.scene.primitives.add(primitive);
    
    // 存储到内部Map中便于管理
    this.primitives.set(id, scenePrimitive);
    
    // 记录图元类型，便于分类管理
    if (primitiveOptions.type) {
      if (!this.primitiveTypes.has(primitiveOptions.type)) {
        this.primitiveTypes.set(primitiveOptions.type, new Set());
      }
      this.primitiveTypes.get(primitiveOptions.type).add(id);
    }
    
    return scenePrimitive;
  }

  /**
   * 创建点图元（高性能大量点渲染）
   * @param {Array} positions - 点位置数组
   * @param {Object} options - 点选项
   * @param {String} id - 图元ID
   * @returns {Primitive} 点图元
   */
  createPointPrimitive(positions, options = {}, id) {
    if (!this.cesiumManager || !this.cesiumManager.viewer) {
      throw new Error('Cesium manager or viewer is not initialized');
    }

    const defaultOptions = {
      color: Cesium.Color.WHITE,
      pixelSize: 5.0,
      translucent: false
    };
    
    const pointOptions = Object.assign({}, defaultOptions, options);
    
    // 创建几何实例
    const geometryInstances = positions.map((position, index) => {
      return new Cesium.GeometryInstance({
        geometry: new Cesium.Geometry({
          attributes: {
            position: new Cesium.GeometryAttribute({
              componentDatatype: Cesium.ComponentDatatype.DOUBLE,
              componentsPerAttribute: 3,
              values: new Float64Array(position)
            }),
            color: Cesium.ColorGeometryInstanceAttribute.fromColor(pointOptions.color)
          },
          primitiveType: Cesium.PrimitiveType.POINTS,
          boundingSphere: Cesium.BoundingSphere.fromVertices(position)
        }),
        id: `${id || 'point'}_${index}`
      });
    });
    
    // 创建图元
    const primitive = new Cesium.Primitive({
      geometryInstances: geometryInstances,
      appearance: new Cesium.PerInstanceColorAppearance({
        flat: true,
        translucent: pointOptions.translucent,
        renderState: {
          lineWidth: Math.min(pointOptions.pixelSize, this.cesiumManager.viewer.scene.maximumAliasedLineWidth)
        }
      }),
      type: 'point'
    });
    
    return this.add(primitive, id || this._generateId());
  }

  /**
   * 创建线图元（高性能大量线渲染）
   * @param {Array} polylines - 线条数组，每个包含positions属性
   * @param {Object} options - 线选项
   * @param {String} id - 图元ID
   * @returns {Primitive} 线图元
   */
  createPolylinePrimitive(polylines, options = {}, id) {
    if (!this.cesiumManager || !this.cesiumManager.viewer) {
      throw new Error('Cesium manager or viewer is not initialized');
    }

    const defaultOptions = {
      color: Cesium.Color.WHITE,
      width: 2.0,
      translucent: false
    };
    
    const polylineOptions = Object.assign({}, defaultOptions, options);
    
    // 创建几何实例
    const geometryInstances = polylines.map((polyline, index) => {
      return new Cesium.GeometryInstance({
        geometry: new Cesium.PolylineGeometry({
          positions: polyline.positions.map(pos => 
            new Cesium.Cartesian3.fromDegrees(pos.longitude, pos.latitude, pos.height || 0)
          ),
          width: polylineOptions.width,
          vertexFormat: Cesium.PolylineMaterialAppearance.VERTEX_FORMAT
        }),
        id: `${id || 'polyline'}_${index}`,
        attributes: {
          color: Cesium.ColorGeometryInstanceAttribute.fromColor(polylineOptions.color)
        }
      });
    });
    
    // 创建图元
    const primitive = new Cesium.Primitive({
      geometryInstances: geometryInstances,
      appearance: new Cesium.PolylineMaterialAppearance({
        material: new Cesium.Material({
          fabric: {
            type: 'Color',
            uniforms: {
              color: polylineOptions.color
            }
          }
        }),
        translucent: polylineOptions.translucent
      }),
      type: 'polyline'
    });
    
    return this.add(primitive, id || this._generateId());
  }

  /**
   * 创建多边形图元（高性能大量多边形渲染）
   * @param {Array} polygons - 多边形数组，每个包含positions属性
   * @param {Object} options - 多边形选项
   * @param {String} id - 图元ID
   * @returns {Primitive} 多边形图元
   */
  createPolygonPrimitive(polygons, options = {}, id) {
    if (!this.cesiumManager || !this.cesiumManager.viewer) {
      throw new Error('Cesium manager or viewer is not initialized');
    }

    const defaultOptions = {
      material: Cesium.Color.WHITE,
      translucent: false,
      outline: false,
      outlineColor: Cesium.Color.BLACK,
      outlineWidth: 1.0
    };
    
    const polygonOptions = Object.assign({}, defaultOptions, options);
    
    // 创建几何实例
    const geometryInstances = polygons.map((polygon, index) => {
      const cartesianPositions = polygon.positions.map(pos => 
        Cesium.Cartesian3.fromDegrees(pos.longitude, pos.latitude, pos.height || 0)
      );
      
      return new Cesium.GeometryInstance({
        geometry: new Cesium.PolygonGeometry({
          polygonHierarchy: new Cesium.PolygonHierarchy(cartesianPositions),
          height: polygon.height || 0,
          extrudedHeight: polygon.extrudedHeight,
          vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
        }),
        id: `${id || 'polygon'}_${index}`,
        attributes: {
          color: Cesium.ColorGeometryInstanceAttribute.fromColor(polygonOptions.material)
        }
      });
    });
    
    // 创建图元
    const primitive = new Cesium.Primitive({
      geometryInstances: geometryInstances,
      appearance: new Cesium.PerInstanceColorAppearance({
        flat: true,
        translucent: polygonOptions.translucent
      }),
      type: 'polygon'
    });
    
    return this.add(primitive, id || this._generateId());
  }

  /**
   * 创建批量图元（用于高性能渲染大量相同或相似的图元）
   * @param {Array} instances - 几何实例数组
   * @param {Object} appearance - 外观配置
   * @param {String} type - 图元类型
   * @param {String} id - 图元ID
   * @returns {Primitive} 批量图元
   */
  createBatchPrimitive(instances, appearance, type, id) {
    if (!this.cesiumManager || !this.cesiumManager.viewer) {
      throw new Error('Cesium manager or viewer is not initialized');
    }

    const primitive = new Cesium.Primitive({
      geometryInstances: instances,
      appearance: appearance,
      type: type
    });
    
    return this.add(primitive, id || this._generateId());
  }

  /**
   * 创建组合图元（将多个图元组合为一个图元以提高性能）
   * @param {Array} primitives - 图元配置数组
   * @param {String} id - 组合图元ID
   * @returns {Primitive} 组合图元
   */
  createCompositePrimitive(primitives, id) {
    if (!this.cesiumManager || !this.cesiumManager.viewer) {
      throw new Error('Cesium manager or viewer is not initialized');
    }

    const compositePrimitive = new Cesium.PrimitiveCollection();
    
    primitives.forEach((primitiveConfig, index) => {
      let primitive;
      switch (primitiveConfig.type) {
        case 'point':
          primitive = this.createPointPrimitive(
            primitiveConfig.positions, 
            primitiveConfig.options, 
            `${id}_point_${index}`
          );
          break;
        case 'polyline':
          primitive = this.createPolylinePrimitive(
            primitiveConfig.polylines, 
            primitiveConfig.options, 
            `${id}_polyline_${index}`
          );
          break;
        case 'polygon':
          primitive = this.createPolygonPrimitive(
            primitiveConfig.polygons, 
            primitiveConfig.options, 
            `${id}_polygon_${index}`
          );
          break;
        default:
          // 处理其他类型的图元
          primitive = new Cesium.Primitive(primitiveConfig);
      }
      
      compositePrimitive.add(primitive);
    });
    
    // 将组合图元添加到场景中
    const scenePrimitive = this.cesiumManager.viewer.scene.primitives.add(compositePrimitive);
    this.primitives.set(id, scenePrimitive);
    this.primitiveTypes.set('composite', new Set([id]));
    
    return scenePrimitive;
  }

  /**
   * 根据类型获取图元
   * @param {String} type - 图元类型
   * @returns {Array} 图元数组
   */
  getByType(type) {
    const typeIds = this.primitiveTypes.get(type);
    if (!typeIds) return [];
    
    return Array.from(typeIds).map(id => this.primitives.get(id)).filter(p => p);
  }

  /**
   * 批量显示或隐藏指定类型的图元
   * @param {String} type - 图元类型
   * @param {Boolean} show - 是否显示
   */
  setShowByType(type, show) {
    const primitives = this.getByType(type);
    primitives.forEach(primitive => {
      primitive.show = show;
    });
  }

  /**
   * 优化大量图元渲染性能
   * @param {String} type - 图元类型
   * @param {Object} options - 优化选项
   */
  optimizePerformance(type, options = {}) {
    const defaultOptions = {
      clustering: false, // 是否启用聚合
      clusteringDistance: 50, // 聚合距离
      levelOfDetail: true, // 是否启用细节层次
      maxVisualDistance: 100000, // 最大可视距离
      minVisualDistance: 1000 // 最小可视距离时的简化距离
    };
    
    const optimizeOptions = Object.assign({}, defaultOptions, options);
    
    // 根据类型获取图元
    const primitives = this.getByType(type);
    
    if (optimizeOptions.levelOfDetail) {
      // 实现细节层次优化逻辑
      console.log(`Applying LOD optimization to ${type} primitives`);
    }
    
    if (optimizeOptions.clustering) {
      // 实现聚合优化逻辑
      console.log(`Applying clustering optimization to ${type} primitives`);
    }
  }

  /**
   * 应用视锥剔除优化
   * @param {String} idOrPrimitive - 图元ID或图元对象
   */
  applyFrustumCulling(idOrPrimitive) {
    let primitive;
    if (typeof idOrPrimitive === 'string') {
      primitive = this.primitives.get(idOrPrimitive);
    } else {
      primitive = idOrPrimitive;
    }
    
    if (primitive) {
      // 启用视锥剔除
      primitive.cull = true;
    }
  }

  /**
   * 应用视距优化
   * @param {String} idOrPrimitive - 图元ID或图元对象
   * @param {Object} options - 视距选项
   */
  applyDistanceDisplayCondition(idOrPrimitive, options = {}) {
    const defaultOptions = {
      near: 0,
      far: Number.MAX_VALUE
    };
    
    const distanceOptions = Object.assign({}, defaultOptions, options);
    
    let primitive;
    if (typeof idOrPrimitive === 'string') {
      primitive = this.primitives.get(idOrPrimitive);
    } else {
      primitive = idOrPrimitive;
    }
    
    if (primitive) {
      // 设置显示距离条件
      primitive.distanceDisplayCondition = new Cesium.DistanceDisplayCondition(
        distanceOptions.near,
        distanceOptions.far
      );
    }
  }

  /**
   * 从场景中移除Primitive
   * @param {String|Primitive} idOrPrimitive - Primitive的ID或Primitive对象本身
   * @returns {Boolean} 是否成功移除
   */
  remove(idOrPrimitive) {
    if (!this.cesiumManager || !this.cesiumManager.viewer) {
      return false;
    }

    let primitive;
    let primitiveId;
    if (typeof idOrPrimitive === 'string') {
      primitiveId = idOrPrimitive;
      primitive = this.primitives.get(idOrPrimitive);
      if (!primitive) {
        return false;
      }
      this.primitives.delete(idOrPrimitive);
    } else {
      primitive = idOrPrimitive;
      // 从Map中找到并删除对应的条目
      for (const [id, prim] of this.primitives.entries()) {
        if (prim === primitive) {
          primitiveId = id;
          this.primitives.delete(id);
          break;
        }
      }
    }

    // 从类型分类中移除
    if (primitiveId) {
      for (const [type, ids] of this.primitiveTypes.entries()) {
        if (ids.has(primitiveId)) {
          ids.delete(primitiveId);
          if (ids.size === 0) {
            this.primitiveTypes.delete(type);
          }
          break;
        }
      }
    }

    return this.cesiumManager.viewer.scene.primitives.remove(primitive);
  }

  /**
   * 根据ID获取Primitive
   * @param {String} id - Primitive的ID
   * @returns {Primitive|undefined} Primitive对象或undefined
   */
  getById(id) {
    return this.primitives.get(id);
  }

  /**
   * 获取所有Primitive对象
   * @returns {Array} Primitive对象数组
   */
  getAll() {
    return Array.from(this.primitives.values());
  }

  /**
   * 根据条件筛选Primitive
   * @param {Function} predicate - 筛选条件函数
   * @returns {Array} 符合条件的Primitive数组
   */
  filter(predicate) {
    const result = [];
    for (const [id, primitive] of this.primitives.entries()) {
      if (predicate(primitive, id)) {
        result.push(primitive);
      }
    }
    return result;
  }

  /**
   * 清空所有Primitive
   */
  clear() {
    if (!this.cesiumManager || !this.cesiumManager.viewer) {
      return;
    }

    // 移除所有Primitive
    this.primitives.forEach((primitive, id) => {
      this.cesiumManager.viewer.scene.primitives.remove(primitive);
    });
    
    // 清空Map
    this.primitives.clear();
    this.primitiveTypes.clear();
  }

  /**
   * 获取Primitive数量
   * @returns {Number} Primitive数量
   */
  getCount() {
    return this.primitives.size;
  }

  /**
   * 显示或隐藏Primitive
   * @param {String|Primitive} idOrPrimitive - Primitive的ID或Primitive对象
   * @param {Boolean} show - 是否显示
   */
  setShow(idOrPrimitive, show) {
    let primitive;
    if (typeof idOrPrimitive === 'string') {
      primitive = this.primitives.get(idOrPrimitive);
    } else {
      primitive = idOrPrimitive;
    }
    
    if (primitive) {
      primitive.show = show;
    }
  }

  /**
   * 批量添加Primitive
   * @param {Array} primitives - Primitive配置数组
   * @returns {Array} 添加的Primitive对象数组
   */
  addBatch(primitives) {
    const addedPrimitives = [];
    primitives.forEach(primitiveOptions => {
      const primitive = this.add(primitiveOptions);
      addedPrimitives.push(primitive);
    });
    return addedPrimitives;
  }

  /**
   * 生成唯一ID
   * @private
   * @returns {String} 唯一ID
   */
  _generateId() {
    return 'primitive_' + Date.now() + '_' + Math.floor(Math.random() * 10000);
  }
}